package cn.net.asiacom.extrator.extra;

import cn.net.asiacom.entity.Detail;
import cn.net.asiacom.entity.OldInvoice;
import cn.net.asiacom.utils.StrUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.PDFTextStripperByArea;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static cn.net.asiacom.config.InvoiceRegexEnum.*;


/**
 * 处理电子发票识别类
 * 旧版发票提取类（PdfInvoiceExtractor），
 * 旧版全电发票识别类，通过加载和解析PDF文件，
 * 使用正则表达式匹配提取关键信息，包括发票代码、发票号码、开票日期、校验码、金额、税额、总计、销售方名称等
 */
public class OldPdfInvoiceExtractor {
    public static OldInvoice extract(File file) throws IOException {
        // 创建一个新的发票对象
        OldInvoice invoice = new OldInvoice();
 
        // 加载 PDF 文件并获取第一页
//        PDDocument doc = PDDocument.load(file);
        PDDocument doc = Loader.loadPDF(file);
        PDPage firstPage = doc.getPage(0);
 
        // 获取页面宽度
        int pageWidth = Math.round(firstPage.getCropBox().getWidth());
 
        // 创建 PDF 文本提取工具
        PDFTextStripper textStripper = new PDFTextStripper();
        textStripper.setSortByPosition(true);
 
        // 提取整个 PDF 文本内容
        String fullText = textStripper.getText(doc);
 
        // 如果页面旋转了，重新计算页面宽度
        if (firstPage.getRotation() != 0) {
            pageWidth = Math.round(firstPage.getCropBox().getHeight());
        }
 
        // 替换文本中的全角字符为半角字符
        String allText = StrUtil.replace(fullText);
 
        // 使用正则表达式匹配和提取发票信息
        {
            Pattern pattern = Pattern.compile(REGULAR_A.getRegex());
            Pattern patternNumber = Pattern.compile(REGULAR_A_1.getRegex());
            Pattern patternNumberReplace = Pattern.compile(REGULAR_A_1R.getRegex());
            Pattern patternDate = Pattern.compile(REGULAR_A_2.getRegex());
            Pattern patternCode = Pattern.compile(REGULAR_A_3.getRegex());
            Pattern patternCodeReplace = Pattern.compile(REGULAR_A_3R.getRegex());
 
            Matcher matcher = pattern.matcher(allText);
            while (matcher.find()) {
                if (matcher.group("machineNumber") != null) {
                    invoice.setMachineNumber(matcher.group("machineNumber"));
                } else if (matcher.group("code") != null) {
                    invoice.setCode(matcher.group("code"));
                } else if (matcher.group("number") != null) {
                    invoice.setNumber(matcher.group("number"));
                } else if (matcher.group("date") != null) {
                    String rawDate = matcher.group("date");
                    try {
                        SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
                        SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd");
 
                        Date parsedDate = inputDateFormat.parse(rawDate);
                        String formattedDate = outputDateFormat.format(parsedDate);
                        invoice.setDate(formattedDate);
                    } catch (ParseException e) {
                        System.out.println("无法解析日期：" + rawDate);
                    }
                } else if (matcher.group("checksum") != null) {
                    invoice.setChecksum(matcher.group("checksum"));
                }
 
                if (invoice.getNumber() == null){
                    Matcher matcher2 = patternNumber.matcher(allText);
                    if (matcher2.find()) {
                        invoice.setNumber(matcher2.group("number"));
                    }
                    if (invoice.getNumber() == null){
                        Matcher matcher2Replace = patternNumberReplace.matcher(allText);
                        while (matcher2Replace.find()) {
                            String firstNumber = matcher2Replace.group("number");
                            String secondNumber = matcher2Replace.group(2);
                            invoice.setNumber(firstNumber + secondNumber);
                        }
                    }
                }
 
                if (invoice.getDate() == null){
                    Matcher matcher3 = patternDate.matcher(allText);
                    if (matcher3.find()) {
                        String rawDate = matcher3.group("date");
 
                        try {
                            SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyyMM月dd日");
                            SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd");
 
                            Date parsedDate = inputDateFormat.parse(rawDate);
                            String formattedDate = outputDateFormat.format(parsedDate);
 
                            invoice.setDate(formattedDate);
                        } catch (Exception e) {
                            System.out.println("无法解析日期：" + rawDate);
                        }
                    }
                }
 
                if (invoice.getCode() == null){
                    Matcher matcher4 = patternCode.matcher(allText);
                    if (matcher4.find()) {
                        invoice.setCode(matcher4.group("code"));
                    }
                    if (invoice.getCode() == null){
                        Matcher matcher4Replace = patternCodeReplace.matcher(allText);
                        while (matcher4Replace.find()) {
                            String firstCode = matcher4Replace.group("code");
                            String secondCode = matcher4Replace.group(2);
                            invoice.setCode(secondCode + firstCode);
                        }
                    }
                }
            }
        }
 
        {
            // 金额、税额提取正则，匹配形如 "合计¥?金额¥?税额" 的文本
            Pattern pattern = Pattern.compile(REGULAR_B.getRegex());
            Matcher matcher = pattern.matcher(allText);
            if (matcher.find()) {
                try {
                    invoice.setAmount(new BigDecimal(matcher.group("amount")));
                } catch (Exception e) {
                    // 不处理
                }
                try {
                    invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));
                } catch (Exception e) {
                    invoice.setTaxAmount(new BigDecimal(0));
                }
            }
        }

        // 如果未取到，合计金额提取正则，用于匹配结果有误的修正
        if (null == invoice.getAmount()) {
            Pattern pattern = Pattern.compile(REGULAR_B_1.getRegex());
            Matcher matcher = pattern.matcher(fullText);
            if (matcher.find()) {
                try {
                    invoice.setAmount(new BigDecimal(matcher.group("amount")));
                } catch (Exception e) {
                    invoice.setAmount(new BigDecimal(0));
                }
                try {
                    invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));
                } catch (Exception e) {
                    invoice.setTaxAmount(new BigDecimal(0));
                }
            }
        }
 
        {
            Pattern pattern = Pattern.compile(REGULAR_C.getRegex());

            Matcher matcher = pattern.matcher(allText);

            if (matcher.find()) {
                invoice.setTotalAmountString(matcher.group("amountString"));

                try {
                    invoice.setTotalAmount(new BigDecimal(matcher.group("amount")));
                } catch (Exception e) {
                    invoice.setTotalAmount(new BigDecimal(0));
                }
            }
        }
 
        {
            Pattern pattern = Pattern.compile(REGULAR_D.getRegex());
            Matcher matcher = pattern.matcher(allText);
 
            if (matcher.find()) {
                invoice.setPayee(matcher.group("payee"));
                invoice.setReviewer(matcher.group("reviewer"));
                invoice.setDrawer(matcher.group("drawer"));
            }
 
            if (allText.indexOf("通行费") > 0 && allText.indexOf("车牌号") > 0) {
                invoice.setType("通行费");
            }
        }
 
        {
            Pattern type00Pattern = Pattern.compile(REGULAR_E.getRegex());
            Matcher m00 = type00Pattern.matcher(allText);
            if (m00.find()) {
                invoice.setTitle(m00.group("p").replaceAll(REGULAR_E_AUX.getRegex(), "") + "通发票");
                if (null == invoice.getType()) {
                    invoice.setType("普通发票");
                }
            } else {
                Pattern type01Pattern = Pattern.compile(REGULAR_E_1.getRegex());
                Matcher m01 = type01Pattern.matcher(allText);
                if (m01.find()) {
                    invoice.setTitle(m01.group("p").replaceAll(REGULAR_E_AUX.getRegex(), "") + "用发票");
                    if (null == invoice.getType()) {
                        invoice.setType("专用发票");
                    }
                }
            }
        }

        PDFKeyWordPosition kwp = new PDFKeyWordPosition();

        Map<String, List<Position>> positionListMap = kwp.getCoordinate(Arrays.asList("机器编号", "税率", "价税合计", "合计", "开票日期", "规格型号", "车牌号", "开户行及账号", "密", "码", "区"), doc);

        PDFTextStripperByArea stripper = new PDFTextStripperByArea();
        stripper.setSortByPosition(true);

        PDFTextStripperByArea detailStripper = new PDFTextStripperByArea();
        detailStripper.setSortByPosition(true);
        {
            Position machineNumber;
            if (positionListMap.get("机器编号").size() > 0) {
                machineNumber = positionListMap.get("机器编号").get(0);
            } else {
                machineNumber = positionListMap.get("开票日期").get(0);
                machineNumber.setY(machineNumber.getY() + 30);
            }
            Position taxRate = positionListMap.get("税率").get(0);
            Position totalAmount = positionListMap.get("价税合计").get(0);
            Position amount = positionListMap.get("合计").get(0);
            Position model = null;
            if (!positionListMap.get("规格型号").isEmpty()) {
                model = positionListMap.get("规格型号").get(0);
            } else {
                model = positionListMap.get("车牌号").get(0);
                model.setX(model.getX() - 15);
            }

            List<Position> account = positionListMap.get("开户行及账号");

            Position buyer;
            Position seller;

            if (account.size() < 2) {
                buyer = new Position(51, 122);
                seller = new Position(51, 341);
            } else {
                buyer = account.get(0);
                seller = account.get(1);
            }

            int maqX = 370;

            List<Position> mi = positionListMap.get("密");
            List<Position> ma = positionListMap.get("码");
            List<Position> qu = positionListMap.get("区");

            for (Position position : mi) {
                float x1 = position.getX();
                for (Position value : ma) {
                    float x2 = value.getX();
                    if (Math.abs(x1 - x2) < 5) {
                        for (Position item : qu) {
                            float x3 = item.getX();
                            if (Math.abs(x2 - x3) < 5) {
                                maqX = Math.round((x1 + x2 + x3) / 3);
                            }
                        }
                    }
                }
            }

            {
            int x = Math.round(model.getX()) - 13;
            int y = Math.round(taxRate.getY()) + 5;
            int h = Math.round(amount.getY()) - Math.round(taxRate.getY()) - 25;

            detailStripper.addRegion("detail", new Rectangle(0, y, pageWidth, h));
            stripper.addRegion("detailName", new Rectangle(0, y, x, h));
            stripper.addRegion("detailPrice", new Rectangle(x, y, pageWidth, h));
            }

            {
                int x = maqX + 10;
                int y = Math.round(machineNumber.getY()) + 10;
                int w = pageWidth - maqX - 10;
                int h = Math.round(taxRate.getY() - 5) - y;

                stripper.addRegion("password", new Rectangle(x, y, w, h));
            }

            {
                int x = Math.round(buyer.getX()) - 15;
                int y = Math.round(machineNumber.getY()) + 10;
                int w = maqX - x - 5;
                int h = Math.round(buyer.getY()) - y + 20;

                stripper.addRegion("buyer", new Rectangle(x, y, w, h));
            }

            {
                int x = Math.round(seller.getX()) - 15;
                int y = Math.round(totalAmount.getY()) + 10;
                int w = maqX - x - 5;
                int h = Math.round(seller.getY()) - y + 20;

                stripper.addRegion("seller", new Rectangle(x, y, w, h));
            }
        }

        stripper.extractRegions(firstPage);
        detailStripper.extractRegions(firstPage);
        doc.close();

        invoice.setPassword(StringUtils.trim(stripper.getTextForRegion("password")));

        {
            String buyer = StrUtil.replace(stripper.getTextForRegion("buyer"));
            Pattern pattern = Pattern.compile(REGULAR_F.getRegex());
 
            Matcher matcher = pattern.matcher(buyer);
 
            while (matcher.find()) {
                if (matcher.group("name") != null) {
                    invoice.setBuyerName(matcher.group("name"));
                }
                else if (matcher.group("code") != null) {
                    invoice.setBuyerCode(matcher.group("code"));
                }
                else if (matcher.group("address") != null) {
                    invoice.setBuyerAddress(matcher.group("address"));
                }
                else if (matcher.group("account") != null) {
                    invoice.setBuyerAccount(matcher.group("account"));
                }
                else if (matcher.group("account2") != null) {
                    invoice.setBuyerAccount(matcher.group("account2"));
                }
            }
        }
 
        {
            String seller = StrUtil.replace(stripper.getTextForRegion("seller"));
 
            Pattern pattern = Pattern.compile(REGULAR_F.getRegex());
 
            Matcher matcher = pattern.matcher(seller);
 
            while (matcher.find()) {
                if (matcher.group("name") != null) {
                    if (matcher.group("name").contains("出有限公司")){
                        String replace = matcher.group("name").replace("出有限公司", "出版社有限公司");
                        invoice.setSellerName(replace);
                    } else if (matcher.group("name").contains("贸有公司")) {
                        String replace = matcher.group("name").replace("贸有公司", "贸易有限公司");
                        invoice.setSellerName(replace);
                    } else {
                        invoice.setSellerName(matcher.group("name"));
                    }
                }
                else if (matcher.group("code") != null) {
                    invoice.setSellerCode(matcher.group("code"));
                }
                else if (matcher.group("address") != null) {
                    invoice.setSellerAddress(matcher.group("address"));
                }
                else if (matcher.group("account") != null) {
                    invoice.setSellerAccount(matcher.group("account"));
                }
            }
        }
        if (invoice.getSellerName() == null){
            Pattern patternReplace = Pattern.compile(REGULAR_FR.getRegex());
 
            Matcher matcherReplace = patternReplace.matcher(allText);
 
            while (matcherReplace.find()) {
                if (matcherReplace.group("name") != null) {
                    if (!matcherReplace.group("name").contains("学院") || !matcherReplace.group("name").contains("大学")){
                        if (matcherReplace.group("name").contains("出有限公司")){
                            String replace = matcherReplace.group("name").replace("出有限公司", "出版社有限公司");
                            invoice.setSellerName(replace);
                        } else if (matcherReplace.group("name").contains("贸有公司")) {
                            String replace = matcherReplace.group("name").replace("贸有公司", "贸易有限公司");
                            invoice.setSellerName(replace);
                        } else {
                            invoice.setSellerName(matcherReplace.group("name"));
                        }
                    }
                }
            }
        }

        {
            List<String> skipList = new ArrayList<>();

            List<Detail> detailList = new ArrayList<>();

            String[] detailPriceStringArray = stripper.getTextForRegion("detailPrice")
                    .replaceAll("　", " ").replaceAll(" ", " ").replaceAll("\r", "").split("\\n");

            for (String detailString : detailPriceStringArray) {
                Detail detail = new Detail();

                detail.setName("");

                String[] itemArray = StringUtils.split(detailString, " ");

                if (2 == itemArray.length) {
                    detail.setAmount(new BigDecimal(itemArray[0]));
                    detail.setTaxAmount(new BigDecimal(itemArray[1]));

                    detailList.add(detail);
                }
                else if (2 < itemArray.length) {
                    detail.setAmount(new BigDecimal(itemArray[itemArray.length - 3]));

                    String taxRate = itemArray[itemArray.length - 2];

                    if (taxRate.indexOf("免税") > 0 || taxRate.indexOf("不征税") > 0 || taxRate.indexOf("出口零税率") > 0
                            || taxRate.indexOf("普通零税率") > 0 || !taxRate.contains("%")) {
                        detail.setTaxRate(new BigDecimal(0));
                        detail.setTaxAmount(new BigDecimal(0));
                    } else {
                        BigDecimal rate = new BigDecimal(Integer.parseInt(taxRate.replaceAll("%", "")));
                        detail.setTaxRate(rate.divide(new BigDecimal(100)));
                        detail.setTaxAmount(new BigDecimal(itemArray[itemArray.length - 1]));
                    }

                    for (int j = 0; j < itemArray.length - 3; j++) {
                        if (itemArray[j].matches(REGULAR_G.getRegex())) {
                            if (null == detail.getCount()) {
                                detail.setCount(new BigDecimal(itemArray[j]));
                            } else {
                                detail.setPrice(new BigDecimal(itemArray[j]));
                            }
                        } else {
                            if (itemArray.length >= j + 1 && !itemArray[j + 1].matches(REGULAR_G.getRegex())) {
                                detail.setUnit(itemArray[j + 1]);
                                detail.setModel(itemArray[j]);
                                j++;
                            } else if (itemArray[j].length() > 2) {
                                detail.setModel(itemArray[j]);
                            } else {
                                detail.setUnit(itemArray[j]);
                            }
                        }
                    }
                    detailList.add(detail);
                } else {
                    skipList.add(detailString);
                }
            }

            String[] detailNameStringArray = stripper.getTextForRegion("detailName").replaceAll("　", " ").replaceAll(" ", " ")
                    .replaceAll("\r", "").split("\\n");
            String[] detailStringArray = StrUtil.replace(detailStripper.getTextForRegion("detail")).replaceAll("\r", "").split("\\n");
            int i = 0, j = 0, h = 0, m = 0;
            Detail lastDetail = null;

            for (String detailString : detailStringArray) {
                if (m < detailNameStringArray.length) {
                    if (detailString.matches(REGULAR_H.getRegex())
                            && !detailString.matches(REGULAR_H_1.getRegex())
                            && detailString.matches(REGULAR_H_2.getRegex())
                            || detailStringArray.length > i + 1
                            && detailStringArray[i + 1].matches(REGULAR_H_3.getRegex())) {
                        if (j < detailList.size()) {
                            lastDetail = detailList.get(j);
                            lastDetail.setName(detailNameStringArray[m]);
                        }
                        j++;
                    } else if (null != lastDetail && StringUtils.isNotBlank(detailNameStringArray[m])) {
                        if (skipList.size() > h) {
                            String skip = skipList.get(h);
                            if (detailString.endsWith(skip)) {
                                if (detailString.equals(skip)) {
                                    m--;
                                } else {
                                    lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);
                                }
                                lastDetail.setModel(lastDetail.getModel() + skip);
                                h++;
                            } else {
                                lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);
                            }
                        } else {
                            lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);
                        }
                    }
                }
                i++;
                m++;
            }

            invoice.setDetailList(detailList);

            if (invoice.getAmount().add(invoice.getTaxAmount()).compareTo(invoice.getTotalAmount()) != 0){
                Pattern patternReplace = Pattern.compile(REGULAR_BR.getRegex());

                Matcher matcherReplace = patternReplace.matcher(allText);

                if (matcherReplace.find()) {
                    try {
                        invoice.setAmount(new BigDecimal(matcherReplace.group("amount")));
                        invoice.setTaxAmount(invoice.getTotalAmount().subtract(invoice.getAmount()));
                    } catch (Exception e) {
                        // 不处理
                    }
                }
            }


            if (invoice.getTotalAmount().compareTo(BigDecimal.ZERO) == 0){
                if (invoice.getAmount().compareTo(BigDecimal.ZERO) == 0){
                    invoice.setAmount((!detailList.isEmpty()) ? detailList.get(0).getAmount() : BigDecimal.ZERO);
                    invoice.setTaxAmount((!detailList.isEmpty()) ? detailList.get(0).getTaxAmount() : BigDecimal.ZERO);
                }
                invoice.setTotalAmount(invoice.getAmount().add(invoice.getTaxAmount()));
            }

        }
        return invoice;
 
    }
 

}